using System;
using System.Collections.Generic;
using System.IO;
using log4net;
using log4net.Config;

namespace CxRomos.Core.Services.Implementation {
    public class Log {
        private static readonly Dictionary<Type, ILog> Loggers = new Dictionary<Type, ILog>();
        private static bool _logInitialized;
        private static readonly object Lock = new object();

        public static string SerializeException(Exception e) {
            return SerializeException(e, string.Empty);
        }

        private static string SerializeException(Exception e, string exceptionMessage) {
            if (e == null) return string.Empty;
            exceptionMessage = string.Format("{0}{1}{2}\n{3}", exceptionMessage, (exceptionMessage == string.Empty) ? string.Empty : "\n\n", e.Message, e.StackTrace);
            if (e.InnerException != null)
                exceptionMessage = SerializeException(e.InnerException, exceptionMessage);
            return exceptionMessage;
        }

        private static ILog GetLogger(Type source) {
            lock(Lock) {
                if (Loggers.ContainsKey(source)) {
                    return Loggers[source];
                }
                ILog logger = LogManager.GetLogger(source);
                Loggers.Add(source, logger);
                return logger;
            }
        }

        public static void Debug(object source, object message) {
            Debug(source.GetType(), message);
        }

        public static void Debug(Type source, object message) {
            GetLogger(source).Debug(message);
        }

        public static void Info(object source, object message) {
            Info(source.GetType(), message);
        }

        public static void Info(Type source, object message) {
            GetLogger(source).Info(message);
        }

        public static void Warn(object source, object message) {
            Warn(source.GetType(), message);
        }

        public static void Warn(Type source, object message) {
            GetLogger(source).Warn(message);
        }

        public static void Error(object source, object message) {
            Error(source.GetType(), message);
        }

        public static void Error(Type source, object message) {
            GetLogger(source).Error(message);
        }

        public static void Fatal(object source, object message) {
            Fatal(source.GetType(), message);
        }

        public static void Fatal(Type source, object message) {
            GetLogger(source).Fatal(message);
        }

        /* Log a message object and exception */

        public static void Debug(object source, object message, Exception exception) {
            Debug(source.GetType(), message, exception);
        }

        public static void Debug(Type source, object message, Exception exception) {
            GetLogger(source).Debug(message, exception);
        }

        public static void Info(object source, object message, Exception exception) {
            Info(source.GetType(), message, exception);
        }

        public static void Info(Type source, object message, Exception exception) {
            GetLogger(source).Info(message, exception);
        }

        public static void Warn(object source, object message, Exception exception) {
            Warn(source.GetType(), message, exception);
        }

        public static void Warn(Type source, object message, Exception exception) {
            GetLogger(source).Warn(message, exception);
        }

        public static void Error(object source, object message, Exception exception) {
            Error(source.GetType(), message, exception);
        }

        public static void Error(Type source, object message, Exception exception) {
            GetLogger(source).Error(message, exception);
        }

        public static void Fatal(object source, object message, Exception exception) {
            Fatal(source.GetType(), message, exception);
        }

        public static void Fatal(Type source, object message, Exception exception) {
            GetLogger(source).Fatal(message, exception);
        }

        private static void Initialize() {
            var logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log4Net.config");
            if (!File.Exists(logFilePath)) {
                logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"bin\Log4Net.config");
            }

            XmlConfigurator.ConfigureAndWatch(new FileInfo(logFilePath));
        }

        public static void EnsureInitialized() {
            if (!_logInitialized) {
                Initialize();
                _logInitialized = true;
            }
        }
 
    }
}